//! List of commonly used strings in Javascript code.

use super::JsString;
use crate::JsStr;
use paste::paste;
use rustc_hash::{FxBuildHasher, FxHashSet};
use std::{collections::HashSet, sync::LazyLock};

macro_rules! well_known_statics {
    ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => {
        $(
            paste!{
                #[doc = "Gets the static `JsString` for `\"" $string "\"`."]
                pub const $name: JsString = const {
                    JsString::from_static_js_str(Self::find_static_js_string($string))
                };
            }
        )+
    };
}

/// List of commonly used strings in Javascript code.
///
/// Any strings defined here are used as a static [`JsString`] instead of allocating on the heap.
#[derive(Debug, Clone, Copy)]
pub struct StaticJsStrings;

impl StaticJsStrings {
    // useful to search at compile time a certain string in the array
    const fn find_static_js_string(candidate: &str) -> &'static JsStr<'static> {
        const fn const_eq(lhs: &[u8], rhs: &[u8]) -> bool {
            if lhs.len() != rhs.len() {
                return false;
            }

            let mut i = 0;
            while i < lhs.len() {
                if lhs[i] != rhs[i] {
                    return false;
                }
                i += 1;
            }
            true
        }

        let len = RAW_STATICS.len();
        let mut i = 0;
        while i < len {
            let Some(s) = RAW_STATICS[i].as_latin1() else {
                // All static strings are latin1 encoded
                unreachable!()
            };
            if const_eq(s, candidate.as_bytes()) {
                return &RAW_STATICS[i];
            }
            i += 1;
        }

        panic!("couldn't find the required string on the common string array");
    }

    /// Gets the `JsString` corresponding to `string`, or `None` if the string
    /// doesn't exist inside the static array.
    #[inline]
    #[must_use]
    pub fn get_string(string: &JsStr<'_>) -> Option<JsString> {
        if string.len() > MAX_STATIC_LENGTH {
            return None;
        }

        let str = *RAW_STATICS_CACHE.get(string)?;

        // SAFETY: Type of T in is `&'static JsStr<'static>`, so this is safe.
        let ptr = unsafe { std::mem::transmute::<&JsStr<'_>, &'static JsStr<'static>>(str) };

        Some(JsString::from_static_js_str(ptr))
    }

    // Some consts are only used on certain features, which triggers the unused lint.
    well_known_statics! {
        (EMPTY_STRING, ""),
        (LENGTH, "length"),
        // Symbols
        (SYMBOL_ASYNC_ITERATOR, "Symbol.asyncIterator"),
        (SYMBOL_HAS_INSTANCE, "Symbol.hasInstance"),
        (SYMBOL_IS_CONCAT_SPREADABLE, "Symbol.isConcatSpreadable"),
        (SYMBOL_ITERATOR, "Symbol.iterator"),
        (SYMBOL_MATCH, "Symbol.match"),
        (SYMBOL_MATCH_ALL, "Symbol.matchAll"),
        (SYMBOL_REPLACE, "Symbol.replace"),
        (SYMBOL_SEARCH, "Symbol.search"),
        (SYMBOL_SPECIES, "Symbol.species"),
        (SYMBOL_SPLIT, "Symbol.split"),
        (SYMBOL_TO_PRIMITIVE, "Symbol.toPrimitive"),
        (SYMBOL_TO_STRING_TAG, "Symbol.toStringTag"),
        (SYMBOL_UNSCOPABLES, "Symbol.unscopables"),
        (FN_SYMBOL_ASYNC_ITERATOR, "[Symbol.asyncIterator]"),
        (FN_SYMBOL_HAS_INSTANCE, "[Symbol.hasInstance]"),
        (FN_SYMBOL_IS_CONCAT_SPREADABLE, "[Symbol.isConcatSpreadable]"),
        (FN_SYMBOL_ITERATOR, "[Symbol.iterator]"),
        (FN_SYMBOL_MATCH, "[Symbol.match]"),
        (FN_SYMBOL_MATCH_ALL, "[Symbol.matchAll]"),
        (FN_SYMBOL_REPLACE, "[Symbol.replace]"),
        (FN_SYMBOL_SEARCH, "[Symbol.search]"),
        (FN_SYMBOL_SPECIES, "[Symbol.species]"),
        (FN_SYMBOL_SPLIT, "[Symbol.split]"),
        (FN_SYMBOL_TO_PRIMITIVE, "[Symbol.toPrimitive]"),
        (FN_SYMBOL_TO_STRING_TAG, "[Symbol.toStringTag]"),
        (FN_SYMBOL_UNSCOPABLES, "[Symbol.unscopables]"),
        // Builtins
        (ARRAY, "Array"),
        (ARRAY_BUFFER, "ArrayBuffer"),
        (SHARED_ARRAY_BUFFER, "SharedArrayBuffer"),
        (ASYNC_FUNCTION, "AsyncFunction"),
        (ASYNC_GENERATOR, "AsyncGenerator"),
        (ASYNC_GENERATOR_FUNCTION, "AsyncGeneratorFunction"),
        (ATOMICS, "Atomics"),
        (BIG_INT, "BigInt"),
        (BOOLEAN, "Boolean"),
        (DATA_VIEW, "DataView"),
        (DATE, "Date"),
        (ERROR, "Error"),
        (AGGREGATE_ERROR, "AggregateError"),
        (EVAL_ERROR, "EvalError"),
        (RANGE_ERROR, "RangeError"),
        (REFERENCE_ERROR, "ReferenceError"),
        (SYNTAX_ERROR, "SyntaxError"),
        (TYPE_ERROR, "TypeError"),
        (URI_ERROR, "URIError"),
        (ESCAPE, "escape"),
        (UNESCAPE, "unescape"),
        (EVAL, "eval"),
        (FUNCTION, "Function"),
        (GENERATOR, "Generator"),
        (GENERATOR_FUNCTION, "GeneratorFunction"),
        (INTL, "Intl"),
        (COLLATOR, "Collator"),
        (LIST_FORMAT, "ListFormat"),
        (LOCALE, "Locale"),
        (PLURAL_RULES, "PluralRules"),
        (SEGMENTER, "Segmenter"),
        (DATE_TIME_FORMAT, "DateTimeFormat"),
        (JSON, "JSON"),
        (MAP, "Map"),
        (MATH, "Math"),
        (NUMBER, "Number"),
        (NUMBER_FORMAT, "NumberFormat"),
        (IS_FINITE, "isFinite"),
        (IS_NAN, "isNaN"),
        (PARSE_INT, "parseInt"),
        (PARSE_FLOAT, "parseFloat"),
        (OBJECT, "Object"),
        (PROMISE, "Promise"),
        (PROXY, "Proxy"),
        (REFLECT, "Reflect"),
        (REG_EXP, "RegExp"),
        (SET, "Set"),
        (STRING, "String"),
        (SYMBOL, "Symbol"),
        (TYPED_ARRAY, "TypedArray"),
        (INT8_ARRAY, "Int8Array"),
        (UINT8_ARRAY, "Uint8Array"),
        (UINT8_CLAMPED_ARRAY, "Uint8ClampedArray"),
        (INT16_ARRAY, "Int16Array"),
        (UINT16_ARRAY, "Uint16Array"),
        (INT32_ARRAY, "Int32Array"),
        (UINT32_ARRAY, "Uint32Array"),
        (BIG_INT64_ARRAY, "BigInt64Array"),
        (BIG_UINT64_ARRAY, "BigUint64Array"),
        #[cfg(feature = "float16")]
        (FLOAT16_ARRAY, "Float16Array"),
        (FLOAT32_ARRAY, "Float32Array"),
        (FLOAT64_ARRAY, "Float64Array"),
        (ENCODE_URI, "encodeURI"),
        (ENCODE_URI_COMPONENT, "encodeURIComponent"),
        (DECODE_URI, "decodeURI"),
        (DECODE_URI_COMPONENT, "decodeURIComponent"),
        (WEAK_REF, "WeakRef"),
        (WEAK_MAP, "WeakMap"),
        (WEAK_SET, "WeakSet"),
        (TEMPORAL, "Temporal"),
        (NOW_TAG, "Temporal.Now"),
        (INSTANT_TAG, "Temporal.Instant"),
        (DURATION_TAG, "Temporal.Duration"),
        (PLAIN_DATE_TAG, "Temporal.PlainDate"),
        (PLAIN_DATETIME_TAG, "Temporal.PlainDateTime"),
        (PLAIN_TIME_TAG, "Temporal.PlainTime"),
        (PLAIN_YM_TAG, "Temporal.PlainYearMonth"),
        (PLAIN_MD_TAG, "Temporal.PlainMonthDay"),
        (ZONED_DT_TAG, "Temporal.ZonedDateTime"),
        (NOW_NAME, "Now"),
        (INSTANT_NAME, "Instant"),
        (DURATION_NAME, "Duration"),
        (PLAIN_DATE_NAME, "PlainDate"),
        (PLAIN_DATETIME_NAME, "PlainDateTime"),
        (PLAIN_TIME_NAME, "PlainTime"),
        (PLAIN_YM_NAME, "PlainYearMonth"),
        (PLAIN_MD_NAME, "PlainMonthDay"),
        (ZONED_DT_NAME, "ZonedDateTime"),
    }
}

const MAX_STATIC_LENGTH: usize = {
    let mut max = 0;
    let mut i = 0;
    while i < RAW_STATICS.len() {
        // TODO: Because `get_index` is not const, we are accessing doc hidden stuff, that may change.
        let len = RAW_STATICS[i].len();
        if len > max {
            max = len;
        }
        i += 1;
    }
    max
};

/// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`.
//
// SAFETY: Must always point to static memory, otherwise this is unsafe.
static RAW_STATICS_CACHE: LazyLock<FxHashSet<&'static JsStr<'static>>> = LazyLock::new(|| {
    RAW_STATICS
        .iter()
        .collect::<HashSet<&'static JsStr<'static>, FxBuildHasher>>()
});

/// Array of raw static strings that aren't reference counted.
const RAW_STATICS: &[JsStr<'static>] = &[
    JsStr::latin1("".as_bytes()),
    // Well known symbols
    JsStr::latin1("Symbol.asyncIterator".as_bytes()),
    JsStr::latin1("[Symbol.asyncIterator]".as_bytes()),
    JsStr::latin1("Symbol.hasInstance".as_bytes()),
    JsStr::latin1("[Symbol.hasInstance]".as_bytes()),
    JsStr::latin1("Symbol.isConcatSpreadable".as_bytes()),
    JsStr::latin1("[Symbol.isConcatSpreadable]".as_bytes()),
    JsStr::latin1("Symbol.iterator".as_bytes()),
    JsStr::latin1("[Symbol.iterator]".as_bytes()),
    JsStr::latin1("Symbol.match".as_bytes()),
    JsStr::latin1("[Symbol.match]".as_bytes()),
    JsStr::latin1("Symbol.matchAll".as_bytes()),
    JsStr::latin1("[Symbol.matchAll]".as_bytes()),
    JsStr::latin1("Symbol.replace".as_bytes()),
    JsStr::latin1("[Symbol.replace]".as_bytes()),
    JsStr::latin1("Symbol.search".as_bytes()),
    JsStr::latin1("[Symbol.search]".as_bytes()),
    JsStr::latin1("Symbol.species".as_bytes()),
    JsStr::latin1("[Symbol.species]".as_bytes()),
    JsStr::latin1("Symbol.split".as_bytes()),
    JsStr::latin1("[Symbol.split]".as_bytes()),
    JsStr::latin1("Symbol.toPrimitive".as_bytes()),
    JsStr::latin1("[Symbol.toPrimitive]".as_bytes()),
    JsStr::latin1("Symbol.toStringTag".as_bytes()),
    JsStr::latin1("[Symbol.toStringTag]".as_bytes()),
    JsStr::latin1("Symbol.unscopables".as_bytes()),
    JsStr::latin1("[Symbol.unscopables]".as_bytes()),
    JsStr::latin1("get [Symbol.species]".as_bytes()),
    JsStr::latin1("get [Symbol.toStringTag]".as_bytes()),
    // Well known builtins
    JsStr::latin1("Array".as_bytes()),
    JsStr::latin1("ArrayBuffer".as_bytes()),
    JsStr::latin1("SharedArrayBuffer".as_bytes()),
    JsStr::latin1("AsyncFunction".as_bytes()),
    JsStr::latin1("AsyncGenerator".as_bytes()),
    JsStr::latin1("AsyncGeneratorFunction".as_bytes()),
    JsStr::latin1("Atomics".as_bytes()),
    JsStr::latin1("BigInt".as_bytes()),
    JsStr::latin1("Boolean".as_bytes()),
    JsStr::latin1("DataView".as_bytes()),
    JsStr::latin1("Date".as_bytes()),
    JsStr::latin1("Error".as_bytes()),
    JsStr::latin1("AggregateError".as_bytes()),
    JsStr::latin1("EvalError".as_bytes()),
    JsStr::latin1("RangeError".as_bytes()),
    JsStr::latin1("ReferenceError".as_bytes()),
    JsStr::latin1("SyntaxError".as_bytes()),
    JsStr::latin1("TypeError".as_bytes()),
    JsStr::latin1("URIError".as_bytes()),
    JsStr::latin1("escape".as_bytes()),
    JsStr::latin1("unescape".as_bytes()),
    JsStr::latin1("eval".as_bytes()),
    JsStr::latin1("Function".as_bytes()),
    JsStr::latin1("Generator".as_bytes()),
    JsStr::latin1("GeneratorFunction".as_bytes()),
    JsStr::latin1("Intl".as_bytes()),
    JsStr::latin1("Collator".as_bytes()),
    JsStr::latin1("ListFormat".as_bytes()),
    JsStr::latin1("Locale".as_bytes()),
    JsStr::latin1("PluralRules".as_bytes()),
    JsStr::latin1("Segmenter".as_bytes()),
    JsStr::latin1("DateTimeFormat".as_bytes()),
    JsStr::latin1("JSON".as_bytes()),
    JsStr::latin1("Map".as_bytes()),
    JsStr::latin1("Math".as_bytes()),
    JsStr::latin1("Number".as_bytes()),
    JsStr::latin1("NumberFormat".as_bytes()),
    JsStr::latin1("isFinite".as_bytes()),
    JsStr::latin1("isNaN".as_bytes()),
    JsStr::latin1("parseInt".as_bytes()),
    JsStr::latin1("parseFloat".as_bytes()),
    JsStr::latin1("Object".as_bytes()),
    JsStr::latin1("Promise".as_bytes()),
    JsStr::latin1("Proxy".as_bytes()),
    JsStr::latin1("Reflect".as_bytes()),
    JsStr::latin1("RegExp".as_bytes()),
    JsStr::latin1("Set".as_bytes()),
    JsStr::latin1("String".as_bytes()),
    JsStr::latin1("Symbol".as_bytes()),
    JsStr::latin1("TypedArray".as_bytes()),
    JsStr::latin1("Int8Array".as_bytes()),
    JsStr::latin1("Uint8Array".as_bytes()),
    JsStr::latin1("Uint8ClampedArray".as_bytes()),
    JsStr::latin1("Int16Array".as_bytes()),
    JsStr::latin1("Uint16Array".as_bytes()),
    JsStr::latin1("Int32Array".as_bytes()),
    JsStr::latin1("Uint32Array".as_bytes()),
    JsStr::latin1("BigInt64Array".as_bytes()),
    JsStr::latin1("BigUint64Array".as_bytes()),
    JsStr::latin1("Float16Array".as_bytes()),
    JsStr::latin1("Float32Array".as_bytes()),
    JsStr::latin1("Float64Array".as_bytes()),
    JsStr::latin1("encodeURI".as_bytes()),
    JsStr::latin1("encodeURIComponent".as_bytes()),
    JsStr::latin1("decodeURI".as_bytes()),
    JsStr::latin1("decodeURIComponent".as_bytes()),
    JsStr::latin1("WeakRef".as_bytes()),
    JsStr::latin1("WeakMap".as_bytes()),
    JsStr::latin1("WeakSet".as_bytes()),
    JsStr::latin1("Temporal".as_bytes()),
    JsStr::latin1("Temporal.Now".as_bytes()),
    JsStr::latin1("Temporal.Instant".as_bytes()),
    JsStr::latin1("Temporal.Duration".as_bytes()),
    JsStr::latin1("Temporal.Calendar".as_bytes()),
    JsStr::latin1("Temporal.PlainDate".as_bytes()),
    JsStr::latin1("Temporal.PlainDateTime".as_bytes()),
    JsStr::latin1("Temporal.PlainMonthDay".as_bytes()),
    JsStr::latin1("Temporal.PlainYearMonth".as_bytes()),
    JsStr::latin1("Temporal.PlainTime".as_bytes()),
    JsStr::latin1("Temporal.TimeZone".as_bytes()),
    JsStr::latin1("Temporal.ZonedDateTime".as_bytes()),
    // Misc
    JsStr::latin1(",".as_bytes()),
    JsStr::latin1(":".as_bytes()),
    // Generic use
    JsStr::latin1("name".as_bytes()),
    JsStr::latin1("length".as_bytes()),
    JsStr::latin1("arguments".as_bytes()),
    JsStr::latin1("prototype".as_bytes()),
    JsStr::latin1("constructor".as_bytes()),
    JsStr::latin1("return".as_bytes()),
    JsStr::latin1("throw".as_bytes()),
    JsStr::latin1("global".as_bytes()),
    JsStr::latin1("globalThis".as_bytes()),
    // typeof
    JsStr::latin1("null".as_bytes()),
    JsStr::latin1("undefined".as_bytes()),
    JsStr::latin1("number".as_bytes()),
    JsStr::latin1("string".as_bytes()),
    JsStr::latin1("symbol".as_bytes()),
    JsStr::latin1("bigint".as_bytes()),
    JsStr::latin1("object".as_bytes()),
    JsStr::latin1("function".as_bytes()),
    // Property descriptor
    JsStr::latin1("value".as_bytes()),
    JsStr::latin1("get".as_bytes()),
    JsStr::latin1("set".as_bytes()),
    JsStr::latin1("writable".as_bytes()),
    JsStr::latin1("enumerable".as_bytes()),
    JsStr::latin1("configurable".as_bytes()),
    // Object object
    JsStr::latin1("assign".as_bytes()),
    JsStr::latin1("create".as_bytes()),
    JsStr::latin1("toString".as_bytes()),
    JsStr::latin1("valueOf".as_bytes()),
    JsStr::latin1("is".as_bytes()),
    JsStr::latin1("seal".as_bytes()),
    JsStr::latin1("isSealed".as_bytes()),
    JsStr::latin1("freeze".as_bytes()),
    JsStr::latin1("isFrozen".as_bytes()),
    JsStr::latin1("isExtensible".as_bytes()),
    JsStr::latin1("hasOwnProperty".as_bytes()),
    JsStr::latin1("isPrototypeOf".as_bytes()),
    JsStr::latin1("setPrototypeOf".as_bytes()),
    JsStr::latin1("getPrototypeOf".as_bytes()),
    JsStr::latin1("defineProperty".as_bytes()),
    JsStr::latin1("defineProperties".as_bytes()),
    JsStr::latin1("deleteProperty".as_bytes()),
    JsStr::latin1("construct".as_bytes()),
    JsStr::latin1("hasOwn".as_bytes()),
    JsStr::latin1("ownKeys".as_bytes()),
    JsStr::latin1("keys".as_bytes()),
    JsStr::latin1("values".as_bytes()),
    JsStr::latin1("entries".as_bytes()),
    JsStr::latin1("fromEntries".as_bytes()),
    JsStr::latin1("propertyIsEnumerable".as_bytes()),
    JsStr::latin1("preventExtensions".as_bytes()),
    JsStr::latin1("getOwnPropertyDescriptor".as_bytes()),
    JsStr::latin1("getOwnPropertyDescriptors".as_bytes()),
    JsStr::latin1("getOwnPropertyNames".as_bytes()),
    JsStr::latin1("getOwnPropertySymbols".as_bytes()),
    JsStr::latin1("__defineGetter__".as_bytes()),
    JsStr::latin1("__defineSetter__".as_bytes()),
    JsStr::latin1("__lookupGetter__".as_bytes()),
    JsStr::latin1("__lookupSetter__".as_bytes()),
    JsStr::latin1("__proto__".as_bytes()),
    JsStr::latin1("get __proto__".as_bytes()),
    JsStr::latin1("set __proto__".as_bytes()),
    // Function object
    JsStr::latin1("apply".as_bytes()),
    JsStr::latin1("bind".as_bytes()),
    JsStr::latin1("call".as_bytes()),
    JsStr::latin1("caller".as_bytes()),
    // Arguments object
    JsStr::latin1("callee".as_bytes()),
    // Array object
    JsStr::latin1("at".as_bytes()),
    JsStr::latin1("from".as_bytes()),
    JsStr::latin1("isArray".as_bytes()),
    JsStr::latin1("of".as_bytes()),
    JsStr::latin1("copyWithin".as_bytes()),
    JsStr::latin1("every".as_bytes()),
    JsStr::latin1("fill".as_bytes()),
    JsStr::latin1("filter".as_bytes()),
    JsStr::latin1("find".as_bytes()),
    JsStr::latin1("findIndex".as_bytes()),
    JsStr::latin1("findLast".as_bytes()),
    JsStr::latin1("findLastIndex".as_bytes()),
    JsStr::latin1("flat".as_bytes()),
    JsStr::latin1("flatMap".as_bytes()),
    JsStr::latin1("forEach".as_bytes()),
    JsStr::latin1("includes".as_bytes()),
    JsStr::latin1("indexOf".as_bytes()),
    JsStr::latin1("join".as_bytes()),
    JsStr::latin1("map".as_bytes()),
    JsStr::latin1("next".as_bytes()),
    JsStr::latin1("reduce".as_bytes()),
    JsStr::latin1("reduceRight".as_bytes()),
    JsStr::latin1("reverse".as_bytes()),
    JsStr::latin1("shift".as_bytes()),
    JsStr::latin1("slice".as_bytes()),
    JsStr::latin1("splice".as_bytes()),
    JsStr::latin1("some".as_bytes()),
    JsStr::latin1("sort".as_bytes()),
    JsStr::latin1("unshift".as_bytes()),
    JsStr::latin1("push".as_bytes()),
    JsStr::latin1("pop".as_bytes()),
    JsStr::latin1("groupBy".as_bytes()),
    JsStr::latin1("toReversed".as_bytes()),
    JsStr::latin1("toSorted".as_bytes()),
    JsStr::latin1("toSpliced".as_bytes()),
    JsStr::latin1("with".as_bytes()),
    // String object
    JsStr::latin1("charAt".as_bytes()),
    JsStr::latin1("charCodeAt".as_bytes()),
    JsStr::latin1("codePointAt".as_bytes()),
    JsStr::latin1("concat".as_bytes()),
    JsStr::latin1("endsWith".as_bytes()),
    JsStr::latin1("fromCharCode".as_bytes()),
    JsStr::latin1("fromCodePoint".as_bytes()),
    JsStr::latin1("lastIndexOf".as_bytes()),
    JsStr::latin1("match".as_bytes()),
    JsStr::latin1("matchAll".as_bytes()),
    JsStr::latin1("normalize".as_bytes()),
    JsStr::latin1("padEnd".as_bytes()),
    JsStr::latin1("padStart".as_bytes()),
    JsStr::latin1("raw".as_bytes()),
    JsStr::latin1("repeat".as_bytes()),
    JsStr::latin1("replace".as_bytes()),
    JsStr::latin1("replaceAll".as_bytes()),
    JsStr::latin1("search".as_bytes()),
    JsStr::latin1("split".as_bytes()),
    JsStr::latin1("startsWith".as_bytes()),
    JsStr::latin1("substr".as_bytes()),
    JsStr::latin1("substring".as_bytes()),
    JsStr::latin1("toLocaleString".as_bytes()),
    JsStr::latin1("toLowerCase".as_bytes()),
    JsStr::latin1("toUpperCase".as_bytes()),
    JsStr::latin1("trim".as_bytes()),
    JsStr::latin1("trimEnd".as_bytes()),
    JsStr::latin1("trimStart".as_bytes()),
    JsStr::latin1("isWellFormed".as_bytes()),
    JsStr::latin1("localeCompare".as_bytes()),
    JsStr::latin1("toWellFormed".as_bytes()),
    JsStr::latin1("toLocaleLowerCase".as_bytes()),
    JsStr::latin1("toLocaleUpperCase".as_bytes()),
    JsStr::latin1("trimLeft".as_bytes()),
    JsStr::latin1("trimRight".as_bytes()),
    JsStr::latin1("anchor".as_bytes()),
    JsStr::latin1("big".as_bytes()),
    JsStr::latin1("blink".as_bytes()),
    JsStr::latin1("bold".as_bytes()),
    JsStr::latin1("fixed".as_bytes()),
    JsStr::latin1("fontcolor".as_bytes()),
    JsStr::latin1("fontsize".as_bytes()),
    JsStr::latin1("italics".as_bytes()),
    JsStr::latin1("link".as_bytes()),
    JsStr::latin1("small".as_bytes()),
    JsStr::latin1("strike".as_bytes()),
    JsStr::latin1("sub".as_bytes()),
    JsStr::latin1("sup".as_bytes()),
    // Number object
    JsStr::latin1("Infinity".as_bytes()),
    JsStr::latin1("NaN".as_bytes()),
    JsStr::latin1("EPSILON".as_bytes()),
    JsStr::latin1("MAX_SAFE_INTEGER".as_bytes()),
    JsStr::latin1("MIN_SAFE_INTEGER".as_bytes()),
    JsStr::latin1("MAX_VALUE".as_bytes()),
    JsStr::latin1("MIN_VALUE".as_bytes()),
    JsStr::latin1("NEGATIVE_INFINITY".as_bytes()),
    JsStr::latin1("POSITIVE_INFINITY".as_bytes()),
    JsStr::latin1("isSafeInteger".as_bytes()),
    JsStr::latin1("isInteger".as_bytes()),
    JsStr::latin1("toExponential".as_bytes()),
    JsStr::latin1("toFixed".as_bytes()),
    JsStr::latin1("toPrecision".as_bytes()),
    // BigInt object
    JsStr::latin1("asIntN".as_bytes()),
    JsStr::latin1("asUintN".as_bytes()),
    // RegExp object
    JsStr::latin1("exec".as_bytes()),
    JsStr::latin1("test".as_bytes()),
    JsStr::latin1("compile".as_bytes()),
    JsStr::latin1("flags".as_bytes()),
    JsStr::latin1("index".as_bytes()),
    JsStr::latin1("lastIndex".as_bytes()),
    JsStr::latin1("hasIndices".as_bytes()),
    JsStr::latin1("ignoreCase".as_bytes()),
    JsStr::latin1("multiline".as_bytes()),
    JsStr::latin1("dotAll".as_bytes()),
    JsStr::latin1("unicode".as_bytes()),
    JsStr::latin1("sticky".as_bytes()),
    JsStr::latin1("source".as_bytes()),
    JsStr::latin1("get hasIndices".as_bytes()),
    JsStr::latin1("get global".as_bytes()),
    JsStr::latin1("get ignoreCase".as_bytes()),
    JsStr::latin1("get multiline".as_bytes()),
    JsStr::latin1("get dotAll".as_bytes()),
    JsStr::latin1("get unicode".as_bytes()),
    JsStr::latin1("get sticky".as_bytes()),
    JsStr::latin1("get flags".as_bytes()),
    JsStr::latin1("get source".as_bytes()),
    // Symbol object
    JsStr::latin1("for".as_bytes()),
    JsStr::latin1("keyFor".as_bytes()),
    JsStr::latin1("description".as_bytes()),
    JsStr::latin1("asyncIterator".as_bytes()),
    JsStr::latin1("hasInstance".as_bytes()),
    JsStr::latin1("species".as_bytes()),
    JsStr::latin1("unscopables".as_bytes()),
    JsStr::latin1("iterator".as_bytes()),
    JsStr::latin1("toStringTag".as_bytes()),
    JsStr::latin1("toPrimitive".as_bytes()),
    JsStr::latin1("isConcatSpreadable".as_bytes()),
    JsStr::latin1("get description".as_bytes()),
    // Map object
    JsStr::latin1("clear".as_bytes()),
    JsStr::latin1("delete".as_bytes()),
    JsStr::latin1("has".as_bytes()),
    JsStr::latin1("size".as_bytes()),
    // Set object
    JsStr::latin1("add".as_bytes()),
    // Reflect object
    // Proxy object
    JsStr::latin1("revocable".as_bytes()),
    // Error objects
    JsStr::latin1("message".as_bytes()),
    // Date object
    JsStr::latin1("toJSON".as_bytes()),
    JsStr::latin1("getDate".as_bytes()),
    JsStr::latin1("getDay".as_bytes()),
    JsStr::latin1("getFullYear".as_bytes()),
    JsStr::latin1("getHours".as_bytes()),
    JsStr::latin1("getMilliseconds".as_bytes()),
    JsStr::latin1("getMinutes".as_bytes()),
    JsStr::latin1("getMonth".as_bytes()),
    JsStr::latin1("getSeconds".as_bytes()),
    JsStr::latin1("getTime".as_bytes()),
    JsStr::latin1("getYear".as_bytes()),
    JsStr::latin1("getUTCDate".as_bytes()),
    JsStr::latin1("getUTCDay".as_bytes()),
    JsStr::latin1("getUTCFullYear".as_bytes()),
    JsStr::latin1("getUTCHours".as_bytes()),
    JsStr::latin1("getUTCMinutes".as_bytes()),
    JsStr::latin1("getUTCMonth".as_bytes()),
    JsStr::latin1("getUTCSeconds".as_bytes()),
    JsStr::latin1("setDate".as_bytes()),
    JsStr::latin1("setFullYear".as_bytes()),
    JsStr::latin1("setHours".as_bytes()),
    JsStr::latin1("setMilliseconds".as_bytes()),
    JsStr::latin1("setMinutes".as_bytes()),
    JsStr::latin1("setMonth".as_bytes()),
    JsStr::latin1("setSeconds".as_bytes()),
    JsStr::latin1("setYear".as_bytes()),
    JsStr::latin1("setTime".as_bytes()),
    JsStr::latin1("setUTCDate".as_bytes()),
    JsStr::latin1("setUTCFullYear".as_bytes()),
    JsStr::latin1("setUTCHours".as_bytes()),
    JsStr::latin1("setUTCMinutes".as_bytes()),
    JsStr::latin1("setUTCMonth".as_bytes()),
    JsStr::latin1("setUTCSeconds".as_bytes()),
    JsStr::latin1("toDateString".as_bytes()),
    JsStr::latin1("toGMTString".as_bytes()),
    JsStr::latin1("toISOString".as_bytes()),
    JsStr::latin1("toTimeString".as_bytes()),
    JsStr::latin1("toUTCString".as_bytes()),
    JsStr::latin1("now".as_bytes()),
    JsStr::latin1("UTC".as_bytes()),
    JsStr::latin1("getTimezoneOffset".as_bytes()),
    JsStr::latin1("getUTCMilliseconds".as_bytes()),
    JsStr::latin1("setUTCMilliseconds".as_bytes()),
    JsStr::latin1("toLocaleDateString".as_bytes()),
    JsStr::latin1("toLocaleTimeString".as_bytes()),
    // JSON object
    JsStr::latin1("parse".as_bytes()),
    JsStr::latin1("stringify".as_bytes()),
    // Promise object
    JsStr::latin1("promise".as_bytes()),
    JsStr::latin1("resolve".as_bytes()),
    JsStr::latin1("reject".as_bytes()),
    JsStr::latin1("all".as_bytes()),
    JsStr::latin1("allSettled".as_bytes()),
    JsStr::latin1("any".as_bytes()),
    JsStr::latin1("race".as_bytes()),
    JsStr::latin1("then".as_bytes()),
    JsStr::latin1("catch".as_bytes()),
    JsStr::latin1("finally".as_bytes()),
    JsStr::latin1("withResolvers".as_bytes()),
    // Iterator object
    JsStr::latin1("Array Iterator".as_bytes()),
    JsStr::latin1("Set Iterator".as_bytes()),
    JsStr::latin1("String Iterator".as_bytes()),
    JsStr::latin1("Map Iterator".as_bytes()),
    JsStr::latin1("For In Iterator".as_bytes()),
    JsStr::latin1("RegExp String Iterator".as_bytes()),
    // Iterator result object
    JsStr::latin1("done".as_bytes()),
    // Math object
    JsStr::latin1("LN10".as_bytes()),
    JsStr::latin1("LN2".as_bytes()),
    JsStr::latin1("LOG10E".as_bytes()),
    JsStr::latin1("LOG2E".as_bytes()),
    JsStr::latin1("PI".as_bytes()),
    JsStr::latin1("SQRT1_2".as_bytes()),
    JsStr::latin1("SQRT2".as_bytes()),
    JsStr::latin1("abs".as_bytes()),
    JsStr::latin1("acos".as_bytes()),
    JsStr::latin1("acosh".as_bytes()),
    JsStr::latin1("asin".as_bytes()),
    JsStr::latin1("asinh".as_bytes()),
    JsStr::latin1("atan".as_bytes()),
    JsStr::latin1("atanh".as_bytes()),
    JsStr::latin1("atan2".as_bytes()),
    JsStr::latin1("cbrt".as_bytes()),
    JsStr::latin1("ceil".as_bytes()),
    JsStr::latin1("clz32".as_bytes()),
    JsStr::latin1("cos".as_bytes()),
    JsStr::latin1("cosh".as_bytes()),
    JsStr::latin1("exp".as_bytes()),
    JsStr::latin1("expm1".as_bytes()),
    JsStr::latin1("floor".as_bytes()),
    JsStr::latin1("fround".as_bytes()),
    JsStr::latin1("hypot".as_bytes()),
    JsStr::latin1("imul".as_bytes()),
    JsStr::latin1("log".as_bytes()),
    JsStr::latin1("log1p".as_bytes()),
    JsStr::latin1("log10".as_bytes()),
    JsStr::latin1("log2".as_bytes()),
    JsStr::latin1("max".as_bytes()),
    JsStr::latin1("min".as_bytes()),
    JsStr::latin1("pow".as_bytes()),
    JsStr::latin1("random".as_bytes()),
    JsStr::latin1("round".as_bytes()),
    JsStr::latin1("sign".as_bytes()),
    JsStr::latin1("sin".as_bytes()),
    JsStr::latin1("sinh".as_bytes()),
    JsStr::latin1("sqrt".as_bytes()),
    JsStr::latin1("tan".as_bytes()),
    JsStr::latin1("tanh".as_bytes()),
    JsStr::latin1("trunc".as_bytes()),
    // TypedArray object
    JsStr::latin1("BYTES_PER_ELEMENT".as_bytes()),
    JsStr::latin1("buffer".as_bytes()),
    JsStr::latin1("byteLength".as_bytes()),
    JsStr::latin1("byteOffset".as_bytes()),
    JsStr::latin1("isView".as_bytes()),
    JsStr::latin1("subarray".as_bytes()),
    JsStr::latin1("get byteLength".as_bytes()),
    JsStr::latin1("get buffer".as_bytes()),
    JsStr::latin1("get byteOffset".as_bytes()),
    JsStr::latin1("get size".as_bytes()),
    JsStr::latin1("get length".as_bytes()),
    // DataView object
    JsStr::latin1("getBigInt64".as_bytes()),
    JsStr::latin1("getBigUint64".as_bytes()),
    JsStr::latin1("getFloat16".as_bytes()),
    JsStr::latin1("getFloat32".as_bytes()),
    JsStr::latin1("getFloat64".as_bytes()),
    JsStr::latin1("getInt8".as_bytes()),
    JsStr::latin1("getInt16".as_bytes()),
    JsStr::latin1("getInt32".as_bytes()),
    JsStr::latin1("getUint8".as_bytes()),
    JsStr::latin1("getUint16".as_bytes()),
    JsStr::latin1("getUint32".as_bytes()),
    JsStr::latin1("setBigInt64".as_bytes()),
    JsStr::latin1("setBigUint64".as_bytes()),
    JsStr::latin1("setFloat16".as_bytes()),
    JsStr::latin1("setFloat32".as_bytes()),
    JsStr::latin1("setFloat64".as_bytes()),
    JsStr::latin1("setInt8".as_bytes()),
    JsStr::latin1("setInt16".as_bytes()),
    JsStr::latin1("setInt32".as_bytes()),
    JsStr::latin1("setUint8".as_bytes()),
    JsStr::latin1("setUint16".as_bytes()),
    JsStr::latin1("setUint32".as_bytes()),
    // WeakRef object
    JsStr::latin1("deref".as_bytes()),
    // Atomic object
    JsStr::latin1("and".as_bytes()),
    JsStr::latin1("compareExchange".as_bytes()),
    JsStr::latin1("exchange".as_bytes()),
    JsStr::latin1("isLockFree".as_bytes()),
    JsStr::latin1("load".as_bytes()),
    JsStr::latin1("or".as_bytes()),
    JsStr::latin1("store".as_bytes()),
    JsStr::latin1("wait".as_bytes()),
    JsStr::latin1("notify".as_bytes()),
    JsStr::latin1("xor".as_bytes()),
    // Intl object
    JsStr::latin1("getCanonicalLocales".as_bytes()),
    JsStr::latin1("get compare".as_bytes()),
    JsStr::latin1("supportedLocalesOf".as_bytes()),
    JsStr::latin1("Intl.Collator".as_bytes()),
    JsStr::latin1("compare".as_bytes()),
    JsStr::latin1("resolvedOptions".as_bytes()),
    JsStr::latin1("Intl.ListFormat".as_bytes()),
    JsStr::latin1("format".as_bytes()),
    JsStr::latin1("formatToParts".as_bytes()),
    JsStr::latin1("get baseName".as_bytes()),
    JsStr::latin1("get calendar".as_bytes()),
    JsStr::latin1("get caseFirst".as_bytes()),
    JsStr::latin1("get collation".as_bytes()),
    JsStr::latin1("get hourCycle".as_bytes()),
    JsStr::latin1("get numeric".as_bytes()),
    JsStr::latin1("get numberingSystem".as_bytes()),
    JsStr::latin1("get language".as_bytes()),
    JsStr::latin1("get script".as_bytes()),
    JsStr::latin1("get region".as_bytes()),
    JsStr::latin1("Intl.Locale".as_bytes()),
    JsStr::latin1("maximize".as_bytes()),
    JsStr::latin1("minimize".as_bytes()),
    JsStr::latin1("baseName".as_bytes()),
    JsStr::latin1("calendar".as_bytes()),
    JsStr::latin1("caseFirst".as_bytes()),
    JsStr::latin1("collation".as_bytes()),
    JsStr::latin1("hourCycle".as_bytes()),
    JsStr::latin1("numeric".as_bytes()),
    JsStr::latin1("numberingSystem".as_bytes()),
    JsStr::latin1("language".as_bytes()),
    JsStr::latin1("script".as_bytes()),
    JsStr::latin1("region".as_bytes()),
    JsStr::latin1("Intl.Segmenter".as_bytes()),
    JsStr::latin1("segment".as_bytes()),
    JsStr::latin1("containing".as_bytes()),
    JsStr::latin1("Segmenter String Iterator".as_bytes()),
    JsStr::latin1("Intl.PluralRules".as_bytes()),
    JsStr::latin1("select".as_bytes()),
    // Temporal object
    JsStr::latin1("get Id".as_bytes()),
    JsStr::latin1("getOffsetNanosecondsFor".as_bytes()),
    JsStr::latin1("getOffsetStringFor".as_bytes()),
    JsStr::latin1("getPlainDateTimeFor".as_bytes()),
    JsStr::latin1("getInstantFor".as_bytes()),
    JsStr::latin1("getPossibleInstantFor".as_bytes()),
    JsStr::latin1("getNextTransition".as_bytes()),
    JsStr::latin1("getPreviousTransition".as_bytes()),
    JsStr::latin1("id".as_bytes()),
    JsStr::latin1("Now".as_bytes()),
    JsStr::latin1("Calendar".as_bytes()),
    JsStr::latin1("Duration".as_bytes()),
    JsStr::latin1("Instant".as_bytes()),
    JsStr::latin1("PlainDate".as_bytes()),
    JsStr::latin1("PlainDateTime".as_bytes()),
    JsStr::latin1("PlainMonthDay".as_bytes()),
    JsStr::latin1("PlainTime".as_bytes()),
    JsStr::latin1("PlainYearMonth".as_bytes()),
    JsStr::latin1("TimeZone".as_bytes()),
    JsStr::latin1("ZonedDateTime".as_bytes()),
    JsStr::latin1("timeZoneId".as_bytes()),
    JsStr::latin1("instant".as_bytes()),
    JsStr::latin1("plainDateTime".as_bytes()),
    JsStr::latin1("plainDateTimeISO".as_bytes()),
    JsStr::latin1("zonedDateTime".as_bytes()),
    JsStr::latin1("zonedDateTimeISO".as_bytes()),
    JsStr::latin1("plainDate".as_bytes()),
    JsStr::latin1("plainDateISO".as_bytes()),
    JsStr::latin1("get epochSeconds".as_bytes()),
    JsStr::latin1("get epochMilliseconds".as_bytes()),
    JsStr::latin1("get epochMicroseconds".as_bytes()),
    JsStr::latin1("get epochNanoseconds".as_bytes()),
    JsStr::latin1("epochSeconds".as_bytes()),
    JsStr::latin1("epochMilliseconds".as_bytes()),
    JsStr::latin1("epochMicroseconds".as_bytes()),
    JsStr::latin1("epochNanoseconds".as_bytes()),
    JsStr::latin1("subtract".as_bytes()),
    JsStr::latin1("until".as_bytes()),
    JsStr::latin1("since".as_bytes()),
    JsStr::latin1("equals".as_bytes()),
    JsStr::latin1("toZonedDateTime".as_bytes()),
    JsStr::latin1("toZonedDateTimeISO".as_bytes()),
    JsStr::latin1("get Years".as_bytes()),
    JsStr::latin1("get Months".as_bytes()),
    JsStr::latin1("get Weeks".as_bytes()),
    JsStr::latin1("get Days".as_bytes()),
    JsStr::latin1("get Hours".as_bytes()),
    JsStr::latin1("get Minutes".as_bytes()),
    JsStr::latin1("get Seconds".as_bytes()),
    JsStr::latin1("get Milliseconds".as_bytes()),
    JsStr::latin1("get Microseconds".as_bytes()),
    JsStr::latin1("get Nanoseconds".as_bytes()),
    JsStr::latin1("get Sign".as_bytes()),
    JsStr::latin1("get blank".as_bytes()),
    JsStr::latin1("years".as_bytes()),
    JsStr::latin1("months".as_bytes()),
    JsStr::latin1("weeks".as_bytes()),
    JsStr::latin1("days".as_bytes()),
    JsStr::latin1("hours".as_bytes()),
    JsStr::latin1("minutes".as_bytes()),
    JsStr::latin1("seconds".as_bytes()),
    JsStr::latin1("milliseconds".as_bytes()),
    JsStr::latin1("microseconds".as_bytes()),
    JsStr::latin1("nanoseconds".as_bytes()),
    JsStr::latin1("blank".as_bytes()),
    JsStr::latin1("negated".as_bytes()),
    JsStr::latin1("total".as_bytes()),
    JsStr::latin1("get calendarId".as_bytes()),
    JsStr::latin1("get year".as_bytes()),
    JsStr::latin1("get month".as_bytes()),
    JsStr::latin1("get monthCode".as_bytes()),
    JsStr::latin1("get day".as_bytes()),
    JsStr::latin1("get dayOfWeek".as_bytes()),
    JsStr::latin1("get dayOfYear".as_bytes()),
    JsStr::latin1("get weekOfYear".as_bytes()),
    JsStr::latin1("get yearOfWeek".as_bytes()),
    JsStr::latin1("get daysInWeek".as_bytes()),
    JsStr::latin1("get daysInMonth".as_bytes()),
    JsStr::latin1("get daysInYear".as_bytes()),
    JsStr::latin1("get monthsInYear".as_bytes()),
    JsStr::latin1("get inLeapYear".as_bytes()),
    JsStr::latin1("calendarId".as_bytes()),
    JsStr::latin1("year".as_bytes()),
    JsStr::latin1("month".as_bytes()),
    JsStr::latin1("monthCode".as_bytes()),
    JsStr::latin1("day".as_bytes()),
    JsStr::latin1("dayOfWeek".as_bytes()),
    JsStr::latin1("dayOfYear".as_bytes()),
    JsStr::latin1("weekOfYear".as_bytes()),
    JsStr::latin1("yearOfWeek".as_bytes()),
    JsStr::latin1("daysInWeek".as_bytes()),
    JsStr::latin1("daysInMonth".as_bytes()),
    JsStr::latin1("daysInYear".as_bytes()),
    JsStr::latin1("monthsInYear".as_bytes()),
    JsStr::latin1("inLeapYear".as_bytes()),
    JsStr::latin1("toPlainYearMonth".as_bytes()),
    JsStr::latin1("toPlainMonthDay".as_bytes()),
    JsStr::latin1("getISOFields".as_bytes()),
    JsStr::latin1("getCalendar".as_bytes()),
    JsStr::latin1("withCalendar".as_bytes()),
    JsStr::latin1("dateFromFields".as_bytes()),
    JsStr::latin1("yearMonthFromFields".as_bytes()),
    JsStr::latin1("monthDayFromFields".as_bytes()),
    JsStr::latin1("dateAdd".as_bytes()),
    JsStr::latin1("dateUntil".as_bytes()),
    JsStr::latin1("era".as_bytes()),
    JsStr::latin1("eraYear".as_bytes()),
    JsStr::latin1("fields".as_bytes()),
    JsStr::latin1("mergeFields".as_bytes()),
    // Console object
    JsStr::latin1("console".as_bytes()),
    JsStr::latin1("assert".as_bytes()),
    JsStr::latin1("debug".as_bytes()),
    JsStr::latin1("error".as_bytes()),
    JsStr::latin1("info".as_bytes()),
    JsStr::latin1("trace".as_bytes()),
    JsStr::latin1("warn".as_bytes()),
    JsStr::latin1("exception".as_bytes()),
    JsStr::latin1("count".as_bytes()),
    JsStr::latin1("countReset".as_bytes()),
    JsStr::latin1("group".as_bytes()),
    JsStr::latin1("groupCollapsed".as_bytes()),
    JsStr::latin1("groupEnd".as_bytes()),
    JsStr::latin1("time".as_bytes()),
    JsStr::latin1("timeLog".as_bytes()),
    JsStr::latin1("timeEnd".as_bytes()),
    JsStr::latin1("dir".as_bytes()),
    JsStr::latin1("dirxml".as_bytes()),
    // Minified name
    JsStr::latin1("a".as_bytes()),
    JsStr::latin1("c".as_bytes()),
    JsStr::latin1("d".as_bytes()),
    JsStr::latin1("e".as_bytes()),
    JsStr::latin1("f".as_bytes()),
    JsStr::latin1("g".as_bytes()),
    JsStr::latin1("h".as_bytes()),
    JsStr::latin1("i".as_bytes()),
    JsStr::latin1("j".as_bytes()),
    JsStr::latin1("k".as_bytes()),
    JsStr::latin1("l".as_bytes()),
    JsStr::latin1("m".as_bytes()),
    JsStr::latin1("n".as_bytes()),
    JsStr::latin1("o".as_bytes()),
    JsStr::latin1("p".as_bytes()),
    JsStr::latin1("q".as_bytes()),
    JsStr::latin1("r".as_bytes()),
    JsStr::latin1("s".as_bytes()),
    JsStr::latin1("t".as_bytes()),
    JsStr::latin1("u".as_bytes()),
    JsStr::latin1("v".as_bytes()),
    JsStr::latin1("w".as_bytes()),
    JsStr::latin1("x".as_bytes()),
    JsStr::latin1("y".as_bytes()),
    JsStr::latin1("z".as_bytes()),
    JsStr::latin1("A".as_bytes()),
    JsStr::latin1("C".as_bytes()),
    JsStr::latin1("D".as_bytes()),
    JsStr::latin1("E".as_bytes()),
    JsStr::latin1("F".as_bytes()),
    JsStr::latin1("G".as_bytes()),
    JsStr::latin1("H".as_bytes()),
    JsStr::latin1("I".as_bytes()),
    JsStr::latin1("J".as_bytes()),
    JsStr::latin1("K".as_bytes()),
    JsStr::latin1("L".as_bytes()),
    JsStr::latin1("M".as_bytes()),
    JsStr::latin1("N".as_bytes()),
    JsStr::latin1("O".as_bytes()),
    JsStr::latin1("P".as_bytes()),
    JsStr::latin1("Q".as_bytes()),
    JsStr::latin1("R".as_bytes()),
    JsStr::latin1("S".as_bytes()),
    JsStr::latin1("T".as_bytes()),
    JsStr::latin1("U".as_bytes()),
    JsStr::latin1("V".as_bytes()),
    JsStr::latin1("W".as_bytes()),
    JsStr::latin1("X".as_bytes()),
    JsStr::latin1("Y".as_bytes()),
    JsStr::latin1("Z".as_bytes()),
    JsStr::latin1("_".as_bytes()),
    JsStr::latin1("$".as_bytes()),
];
